﻿using MathNet.Numerics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace nCoV2019_Predict
{
    public partial class Form1 : Form
    {
        static int useDay = -14;
        DateTime startDay = DateTime.Today.AddDays(useDay);
        public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;

            Run();

            new Thread(() =>
            {
                while (true)
                {
                    var od = GetDataOns();
                    label1.Text = $"更新时间UpdateTime：{od.lastUpdateTime}，确诊Confirm：{od.chinaTotal.confirm}，疑似Suspect：{od.chinaTotal.suspect}，治愈Heal：{od.chinaTotal.heal}，死亡Dead：{od.chinaTotal.dead}";
                    Thread.Sleep(1000 * 60);
                }
            }).Start();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Environment.Exit(0);
        }
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            Run();
        }

        private void Run()
        {
            var data = GetData().OrderBy(i => i.日期Date).ToList();
            if (data.Last().日期Date == DateTime.Today) data.RemoveAt(data.Count - 1);
            toolStripStatusLabel1.Text = data.Last().日期Date.ToString("yyyy-MM-dd") + $" 之后均为预测数据 The data after {data.Last().日期Date.ToString("yyyy-MM-dd")} is predicted";

            var P = CalcP(data);
            Predict(P, data);

            dataGridView1.DataSource = data;

            chart1.Series.Clear();
            new List<string> { "确诊Confirm", "疑似Suspect", "治愈Heal", "死亡Dead" }.ForEach(i => Plot(i, data));
        }
        private double[][] CalcP(List<DataRaw> data)
        {
            var x = new List<double>();
            var yc = new List<double>();
            var ys = new List<double>();
            var yh = new List<double>();
            var yd = new List<double>();
            var d = data.Where(i => (i.日期Date - startDay).TotalDays >= 0).ToList();
            d.ForEach(i =>
            {
                var da = (i.日期Date - startDay).TotalDays;
                x.Add(da);
                yc.Add(i.确诊Confirm);
                ys.Add(i.疑似Suspect);
                yh.Add(i.治愈Heal);
                yd.Add(i.死亡Dead);
            });
            var Pc = Fit.Polynomial(x.ToArray(), yc.ToArray(), 1);
            var Ps = Fit.Polynomial(x.ToArray(), ys.ToArray(), 1);
            var Ph = Fit.Polynomial(x.ToArray(), yh.ToArray(), 1);
            var Pd = Fit.Polynomial(x.ToArray(), yd.ToArray(), 1);
            return new double[][] { Pc, Ps, Ph, Pd };
        }
        private void Predict(double[][] P, List<DataRaw> data)
        {
            var ds = (int)((data.Last().日期Date - startDay).TotalDays);
            for (int i = ds; i < ds + numericUpDown1.Value; i++)
            {
                var confirm = (int)Polynomial.Evaluate(i + 1, P[0]);
                var suspect = (int)Polynomial.Evaluate(i + 1, P[1]);
                var heal = (int)Polynomial.Evaluate(i + 1, P[2]);
                var dead = (int)Polynomial.Evaluate(i + 1, P[3]);
                data.Add(new DataRaw()
                {
                    日期Date = data[0].日期Date.AddDays(data.Count + useDay + 1 + i),
                    confirm = confirm >= 0 ? confirm : 0,
                    suspect = suspect >= 0 ? suspect : 0,
                    heal = heal >= 0 ? heal : 0,
                    dead = dead >= 0 ? dead : 0
                });
            }
        }
        private void Plot(string name, List<DataRaw> data)
        {
            var series = new Series() { Name = name, ChartType = SeriesChartType.Point };
            switch (name)
            {
                case "确诊Confirm": data.ForEach(i => series.Points.AddXY(i.日期Date, i.确诊Confirm)); break;
                case "疑似Suspect": data.ForEach(i => series.Points.AddXY(i.日期Date, i.疑似Suspect)); break;
                case "治愈Heal": data.ForEach(i => series.Points.AddXY(i.日期Date, i.治愈Heal)); break;
                case "死亡Dead": data.ForEach(i => series.Points.AddXY(i.日期Date, i.死亡Dead)); break;
            }
            chart1.Series.Add(series);
        }

        private string Get(string url)
        {
            var r = new WebClient { Encoding = Encoding.UTF8 }.DownloadString(url);
            return JsonConvert.DeserializeObject<RootObject>(r).data;
        }
        private DataRaw[] GetData()
        {
            var r = Get("https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_cn_day_counts");
            var f = Path.Combine(Application.StartupPath, "nCoV2019_Predict_data.json");
            if (File.Exists(f) && !string.IsNullOrWhiteSpace(r))
            {
                File.Delete(f);
            }
            File.WriteAllText(f, r);
            return JsonConvert.DeserializeObject<DataRaw[]>(r);
        }
        private dynamic GetDataOns()
        {
            var r = Get("https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5");
            return JValue.Parse(r);
        }
    }
}